package sweetsaremeat.beehive.View;


import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

import sweetsaremeat.beehive.BeehiveApp;
import sweetsaremeat.beehive.Controller.InputController;
import sweetsaremeat.beehive.Model.Game;
import sweetsaremeat.beehive.Model.Node;
import sweetsaremeat.beehive.Model.Map;
import sweetsaremeat.beehive.Model.Vector2;
import sweetsaremeat.beehive.Model.Node.Side;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.util.FloatMath;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;

public class GameView extends View 
{
	public Camera m_camera;
	
	Game m_game;
	GameAssets m_gameAssets;
	
	Hexagon m_hexagon;
	//List<Node> m_openList = new ArrayList<Node>();
	Stack<Node> m_openList = new Stack<Node>();
	List<Node> m_closedList = new ArrayList<Node>();
	
	boolean m_testBool = false;
	
	public GameView(Context a_context, Game a_game, GameAssets a_gameAssets) 
	{
		super(a_context);
		
		//set game
		m_game = a_game;
		
		//set game assets
		m_gameAssets = a_gameAssets;
		
		//initiate hexagon
		m_hexagon = new Hexagon();

		
	}
	
	protected void onDraw(Canvas a_canvas) 
	{
    	try
    	{
    		//check if camera is not yet initialized
    		if(m_camera == null)
    		{
    			throw new RuntimeException("The camera is NULL");
    		}
    		
    		//draw game
    		DrawGame(a_canvas, BeehiveApp.m_masterController.m_game);
    	}
    	catch(Exception e)
    	{
    		System.out.println("GameView.onDraw ERROR: " + e.toString());
    	}
    }
	
	public void DrawGame(Canvas a_canvas, Game a_game)
	{
		DrawMap(a_canvas, a_game);
	}
	
	private void DrawMap(Canvas a_canvas, Game a_game)
	{
		
		//check if the player has a hexagon (otherwise we can't draw)
		if(a_game.m_player.m_node != null)
		{
			//set the original hexagon's points
			m_hexagon.SetHexagonPoints(m_camera.m_center.x + m_camera.m_pos.x, m_camera.m_center.y + m_camera.m_pos.y, Hexagon.c_size * m_camera.m_scale);
			m_hexagon.CalcPath(); //calc the original path
			
			//clear the open list from old data
			m_openList.clear();
			m_closedList.clear(); //and the closed list as well
			
			//initialize some stuff before drawing
			Path f_pathToDraw = new Path();
			//set offset
			float f_xOffset = 0;
			float f_yOffset = 0;
			int i = 0;
			Node f_currentNode;
			boolean f_drawn;
			
			int counter = 0;//not needed
			
			//draw the first one separately
    		//a_canvas.drawPath(m_hexagon.m_path, m_hexagon.m_paint);
			DrawNode(a_canvas, a_game.m_player.m_node);
    		
    		//add start node to the openList
			m_openList.add(a_game.m_player.m_node);
			//add start node to the closed list
			//NOTE: to not draw the start node multiple times
			m_closedList.add(a_game.m_player.m_node);
			
			//start the draw loop (draws neighbors)
			while(m_openList.size() > 0)
			{
				//pop the first one off the open list
				f_currentNode = m_openList.get(0);
				m_openList.remove(0);
				
				//loop through all sides of the node
				for(Node.Side s : Node.Side.values())
				{
					//check if there is a neighbor on this side
					if(f_currentNode.m_neighbors[s.ordinal()] != null)
					{
						//check if the node is visible
						//TODO it's currently drawing invisible nodes for testing
						if(true) //f_currentNode.m_neighbors[s.ordinal()].m_visible)
						{
							
							//check if it has been drawn
							
							//.. but first!
							//Check if we don't have to! 
							//TODO Optimization idea..?
							//see.. the opposite and the ones on the right/left of the opposite
							//from the one who added it to the open list, can by logic be ignored
							
							
							
							//now check if it's on the closed list
							//NOTE: it's reversed for no real reason
							f_drawn = false;
							for(i = m_closedList.size() - 1; i >= 0; i--)
							{
								//check if the one we are about to draw has already been drawn
								if(f_currentNode.m_neighbors[s.ordinal()] == m_closedList.get(i))
								{
									f_drawn = true;
									break;
								}
							}
							
							//check if it's been drawn
							if(f_drawn)
							{
								continue; //next side
							}
							
							
							//DRAW THE NODE!
							DrawNode(a_canvas, f_currentNode.m_neighbors[s.ordinal()]);
							
							
							//add this node to the closed list 
							//NOTE: so we don't draw this one multiple times!
							m_closedList.add(f_currentNode.m_neighbors[s.ordinal()]);
							
							
							//this is where we should check if we need to draw any more to fill the screen
							//basically ignoring the ones that we won't see anyway
							//TODO the corners won't be drawn because we use continue when one of the x or y is outside
							//	   change to: when one of them is inside we should draw
							/*
							if(f_xOffset > 0) {
								if(m_hexagon.m_center.x + f_xOffset + Node.xOffset * Hexagon.c_size * 0.5f >= m_camera.m_width) {
									continue;
								}
							}
							else {
								
								if(m_hexagon.m_center.x + f_xOffset - Node.xOffset * Hexagon.c_size * 0.5f <= 0) {
									continue;
								}
							}
							
							if(f_yOffset > 0) {
								if(m_hexagon.m_center.y + f_yOffset + Hexagon.c_size * 0.5f >= m_camera.m_height) {
									continue;
								}
							}
							else {
								if(m_hexagon.m_center.y + f_yOffset - Hexagon.c_size * 0.5f <= 0) {
									continue;
								}
							}*/
							
							//add the neighbor to the open list 
							//NOTE: so that we can draw it's neighbors
							m_openList.add(f_currentNode.m_neighbors[s.ordinal()]);
						}
					}
				}//loop through all sides of the node
			}
		}
		else
		{
			throw new RuntimeException("GameView.DrawMap: The player's m_hexagon is NULL.");
		}
	}
	
	
	@Override
	 protected void onSizeChanged(int xNew, int yNew, int xOld, int yOld){
	     super.onSizeChanged(xNew, yNew, xOld, yOld);
	     
	     System.out.println("onSizeChanged to width=" + xNew + " height=" + yNew);
	     
	     m_camera.SetCameraBorders(xNew, yNew);
	}
	
	
	private void DrawNode(Canvas a_canvas, Node a_node)
	{
		//calc the offset
		float f_xOffset = m_camera.GetScreenPosX(a_node.m_pos.x) * m_hexagon.c_size;
		float f_yOffset = m_camera.GetScreenPosY(a_node.m_pos.y) * m_hexagon.c_size;
		
		Path f_pathToDraw = new Path();
		
		//offset the path to draw based of the original
		m_hexagon.m_path.offset(
				f_xOffset, 
				f_yOffset, 
				f_pathToDraw);
		
		
		//draw the hexagon
		a_canvas.drawPath(f_pathToDraw, m_gameAssets.m_hexagonPaint);	
		
		//test draw tagged nodes
		if(a_node.m_tag)
		{
			a_canvas.drawPath(f_pathToDraw, m_gameAssets.m_testPaint);
		}
		
		//if the node is invisible
		if(a_node.m_visible == false)
		{
			//draw a black opacity mask on it
			a_canvas.drawPath(f_pathToDraw, m_gameAssets.m_testOpacityPaint);
		}
		
		//test to draw the paths
		if(a_node.m_isPath)
		{
			//draw the hexagon in a different color
			//a_canvas.drawPath(f_pathToDraw, f_testPaint);
		
			
			for(int n=0; n < 6; n++)
			{
				if(a_node.m_connectedTo[n])
				{
					//draw the path line..
					a_canvas.drawLine(
							m_camera.GetScreenCenterX() + m_camera.GetScreenPosX(a_node.m_pos.x * m_hexagon.c_size),
							m_camera.GetScreenCenterY() + m_camera.GetScreenPosY(a_node.m_pos.y * m_hexagon.c_size),
							m_camera.GetScreenPosX(a_node.m_neighbors[n].m_pos.x * m_hexagon.c_size - a_node.m_pos.x * m_hexagon.c_size) + m_camera.GetScreenCenterX() + m_camera.GetScreenPosX(a_node.m_pos.x * m_hexagon.c_size),
							m_camera.GetScreenPosY(a_node.m_neighbors[n].m_pos.y * m_hexagon.c_size - a_node.m_pos.y * m_hexagon.c_size) + m_camera.GetScreenCenterY() + m_camera.GetScreenPosY(a_node.m_pos.y * m_hexagon.c_size),
							m_gameAssets.m_testPaintStroke);
				}
			}
			
		}
		
		
		
		//test (draw the id)
		a_canvas.drawText("" + a_node.m_id, 
				m_hexagon.m_center.x + f_xOffset, 
				m_hexagon.m_center.y + f_yOffset, 
				m_gameAssets.m_hexagonStrokePaint);
		
		
		
		
		a_canvas.drawPath(f_pathToDraw, m_gameAssets.m_hexagonStrokePaint);//draw the sides of the hexagons
	}

}
